#include <Entities/actor.h>
#include <Game/Game.h>
#include <Skills/event.h>
#include "automatic.h"

namespace skill {
    bool DescendCoolDown::use(Game *g, const std::vector<std::string> &params) {
        if (!Automatic::use(g, params)) return false;
        for (std::pair<std::string, Skill *> it: origin->skillList)
            if (it.second->hasPrefix("_CoolDownSkill_"))
                dynamic_cast<CoolDownSkill *>(it.second)->onDescendCoolDown();
        return true;
    }

    bool DeathCalulation::use(Game *g, const std::vector<std::string> &params) {
        if (!Automatic::use(g, params)) return false;
        int hp = std::stoi(origin->properties["hp"]);
        if (hp > std::stoi(origin->properties["max_hp"])){
            origin->properties["hp"] = origin->properties["max_hp"];
        }
        else if (hp <= 0 ) {
            origin->learnSkill(new skill::TriggeredDeath);
            origin->useLater("TriggeredDeath",{});
        }
        return true;
    }
    Buff::Buff(int r, Entity *sender) : Automatic(){
        this->setName("Buff");
        this->turn = TurnName::BuffTurn;
        this->remaining = r;
        this->hidden = false;
        if (sender != nullptr){
            minor_id = sender->id;
        }
    }

    bool Buff::use(Game *g, const std::vector<std::string> &params) {
        if(!Automatic::use(g, params)) return false;
        if(remaining-- <= 0)
        {
            origin->unlearnSkill(this);
            return false;
        }
        return true;
    }

    bool Buff::onLearn(Game *g) {
        if (stackable) {
            minor_id += "#" + std::to_string(g->nowRound);
            if (origin->skillList[this->name]->hasPrefix("_BuffHelper_")){
                origin->skillList[this->name] = new BuffHelper(this);
            }
            (dynamic_cast<BuffHelper*>(origin->skillList[this->name]))->add(this);
        }
        else {
            if (origin->skillList.find(this->name) != origin->skillList.end()) {
                this->onMerge(origin->skillList[this->name]);
                origin->skillList[this->name] = this;
            }
        }
        return Skill::onLearn(nullptr);
    }
    bool Buff::onMerge(Skill *orig) {
        return true;
    }

    Json::Value Buff::toJson() {
        Json::Value root = Skill::toJson();
        root["remaining"] = remaining;
        return root;
    }

    bool BuffHelper::use(Game *g, const std::vector<std::string> &params) {
        if (!Skill::use(g, params)) return false;
        std::vector<Skill*> buffListCopied;
        for (auto i: buffList){
            Skill* s = i.second;
            buffListCopied.push_back(s);
        }
        for (auto i: buffListCopied){
            origin->useSkill(i, params);
        }
        return true;
    }

    void BuffHelper::remove(std::string minor_id) {
        buffList.erase(minor_id);
        if (buffList.size() == 0){
            origin->unlearnSkill(this);
        }
    }

    void BuffHelper::add(Buff *buff) {
        buffList.insert(make_pair(buff->minor_id, buff));
    }

    Json::Value BuffHelper::toJson() {
        Json::Value root = Skill::toJson();
        for (auto i : buffList)
            root["buffs"].append(i.second->toJson());
        return root;
    }

}